package com.day.newcorp;

import java.io.IOException;
import java.util.Dictionary;
import java.util.Hashtable;

import org.apache.felix.http.api.ExtHttpService;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.newcorp.social.web.SocialCallBackFilter;

/** Rebinds the configurations of services to this bundle, in case
 * 	it is bound to another one. This happens when upgrading a 5.2.0 instance,
 * 	details in #27206
 */
public class Activator implements BundleActivator, ServiceListener {

	private BundleContext ctx;
	private final Logger log = LoggerFactory.getLogger(getClass());

	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void start(BundleContext bc) throws Exception {
		ctx = bc;
		boolean done = false;
		final ServiceReference ref = bc.getServiceReference(ConfigurationAdmin.class.getName());
		if(ref != null) {
			final ConfigurationAdmin ca = (ConfigurationAdmin)bc.getService(ref);
			if(ca != null) {
				log.info("ConfigurationAdmin available at startup, trying to rebind config");
				rebindConfig(ca);
				done = true;
			}
		}

		if(!done) {
			log.info("ConfigurationAdmin not available at startup, will rebind when it is registered");
			bc.addServiceListener(this);
		}

		//Register social call back filter
		
		ServiceReference sRef = bc.getServiceReference(ExtHttpService.class.getName());
		if (sRef != null) {
			Dictionary properties = new Hashtable();
			properties.put("service.pid", SocialCallBackFilter.class.getName());
			properties.put("social.repository", "com.newcorp.social.osgi.SocialUserRepositoryImpl");
			properties.put("sociallogin.redirect.url.format", "/%s/%s/sociallogin.html?tpt=%s");
			ExtHttpService service = (ExtHttpService) bc.getService(sRef);
			service.registerFilter(new SocialCallBackFilter(), "/oauth2callback", properties, 0, null);
			log.debug("######## Registering SocialCallBackFilter");
		}
		

	}

	public void stop(BundleContext bc) throws Exception {
		bc.removeServiceListener(this);
		ctx = null;
	}

	public void serviceChanged(ServiceEvent e) {
		if(e.getType() == ServiceEvent.REGISTERED && ctx != null) {
			final ServiceReference ref = e.getServiceReference();
			final Object o = ctx.getService(ref);
			if(o instanceof ConfigurationAdmin) {
				log.info("ConfigurationAdmin registered, trying to rebind config");
				rebindConfig((ConfigurationAdmin)o);

				// Done, no need to listen anymore
				log.info("Deactivating ServiceListener");
				ctx.removeServiceListener(this);
			}
		}
	}

	/** Attempt to rebind the config to this bundle
	 * @throws InvalidSyntaxException
	 * @throws IOException */
	protected void rebindConfig(ConfigurationAdmin ca) {
		try {
			final String pid1 = "com.day.cq.wcm.foundation.impl.HTTPAuthHandler";
			final String pid2 = "com.day.newcorp.SsoAuthenticationHandler";
			final String filter = "(|(service.pid=" + pid1 + ")(service.pid=" + pid2 + "))";
			final Configuration[] cfgs = ca.listConfigurations(filter);
			if(cfgs != null) {
				for (Configuration cfg : cfgs) {
					final String myLocation = ctx.getBundle().getLocation();
					if(cfg.getBundleLocation() == null) {
						log.info("Config {} is not bound, no changes needed", cfg.getPid());
					} else if(cfg.getBundleLocation().equals(myLocation)) {
						log.info("Config {} already bound to this bundle, no changes needed", cfg.getPid());
					} else {
						// Unbind the config and update it, in case the service is already running.
						// SCR will take care of rebinding it.
						cfg.setBundleLocation(null);
						cfg.update();
						log.info("Config {} unbound and updated", cfg.getPid());
					}
				}
			} else {
				log.info("No configuration to rebind");
			}
		} catch(Exception e) {
			log.error("Exception in rebindConfig", e);
		}
	}
}